package incubator

import (
	proto "github.com/golang/protobuf/proto"
	"encoding/json"
	"fmt"
	"bytes"
	"io/ioutil"
	"net/http"
	"log"
	"strings"
	"encoding/hex"
	keyStore "github.com/ethereum/go-ethereum/accounts/keystore"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/OpenBazaar/openbazaar-go/incubator/rpc"
	"github.com/OpenBazaar/openbazaar-go/repo"
	"path"
	"github.com/OpenBazaar/openbazaar-go/pb"
	"github.com/OpenBazaar/openbazaar-go/core"

	"math/big"
)

type Key struct{
	Address string
	Crypto  string
	ID                string
	version           string
}
type Mywallet struct {
	Password          string
	Privatekey        string
}

func (m *Mywallet) Reset()                    { *m = Mywallet{} }
func (m *Mywallet) String() string            { return proto.CompactTextString(m) }
func (*Mywallet) ProtoMessage()               {}
//post
func (m *Mywallet) GetPassword()(string){
	return m.Password
}
func CreateWallet(passphrase string)(string, string, error){
	repoPath, err := repo.GetRepoPath(false)
	keystore := keyStore.NewKeyStore(path.Join(repoPath, "keystore"), 2, 1)
	a, err := keystore.NewAccount(passphrase)
	if err != nil {
		fmt.Print("%s\n", err)
	}
	keypath := strings.Replace(a.URL.Path,"\\","/",-1)//get key filename
	keyfile :=path.Base(keypath)
	keydata, err := ioutil.ReadFile(a.URL.Path)//read key from keystore
	keyjson, err := ioutil.ReadAll(strings.NewReader(string(keydata)))
	testkey, err := keyStore.DecryptKey(keyjson,passphrase)
	if err != nil {
		log.Fatalf("Failed to connect to the Ethereum client: %v", err)
	}

	//fmt.Printf("%s\n", testkey.Id)
	//fmt.Printf("%s\n", testkey.Address)
	keybyte := crypto.FromECDSA(testkey.PrivateKey)
	var Myprivatekey string = hex.EncodeToString(keybyte)
	walleraddress, error := rpc.ImportRawKey(Myprivatekey,passphrase)
	if error != nil {
		return "","",error
	}
	fmt.Print("import success")
	return walleraddress, keyfile, nil
}

func (*Mywallet) Postkey(PrivateKey string)(){
	var s Mywallet
	s.Privatekey = PrivateKey
	b, err := json.Marshal(s.Privatekey)
	if err != nil {
		fmt.Println("json err:", err)
	}
	body := bytes.NewBuffer([]byte(b))
	res,err := http.Post("http://localhost:9001", "application/json;charset=utf-8", body)
	if err != nil {
		log.Fatal(err)
		return
	}
	result, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
		return
	}
	fmt.Printf("%s", result)
}
func UnmarshalProfile(profilejson []byte)(string,error){
	m := make(map[string]interface{})
	if err := json.Unmarshal(profilejson, &m); err != nil {
		return "string error", err
	}
	keypath:= m["Keypath"].(string)

	return keypath,nil
}
func UnmarshalUTC(UTCjson []byte)(string, error){
	m := make(map[string]interface{})
	if err := json.Unmarshal(UTCjson, &m); err != nil {
		return "string error", err
	}
	UTCaddress:= m["address"].(string)

	return UTCaddress,nil
}
func GetWalletAddress()(string){
	repoPath, err := repo.GetRepoPath(false)
	var profilepath  =  path.Join(repoPath, "root", "profile.json")
	tempprofilebyte, err := ioutil.ReadFile(profilepath)
	if err != nil {
		return ""
	}
	tempprofiledata,err := UnmarshalProfile(tempprofilebyte)
	if err != nil {
		return ""
	}
	tempUTCdata, err := ioutil.ReadFile(path.Join(repoPath, "keystore", tempprofiledata))
	if err != nil {
		return ""
	}
	tempUTCaddress, err := UnmarshalUTC(tempUTCdata)
	if err != nil {
		return ""
	}
	return tempUTCaddress
}
func GetBalance()(int64, int64, error){
	addres := "0x" + GetWalletAddress()
	confirmed, error := rpc.QueryBalance(addres, "latest")
	if error!=nil {
		return 0, 0, error
	}
	all, error := rpc.QueryBalance(addres, "pending")
	if error!=nil {
		return 0, 0, error
	}
	unconfirmed := all - confirmed
	return confirmed, unconfirmed, nil
}
func SpendCoins(n *core.OpenBazaarNode, Amount int64, Address  string)(*rpc.TransactionResult, error){
	from := "0x" + GetWalletAddress()
	var to string
	if !strings.HasPrefix(Address, "0x") {
		to = "0x" + Address
	}else{
		to = Address
	}
	var profile pb.Profile
	profile, error := n.GetProfile()
	if error != nil {
		return nil, error
	}
	amount := big.NewInt(Amount)
	amount.Mul(amount, big.NewInt(1000000))
	amount.Mul(amount, big.NewInt(1000000))
	amount.Mul(amount, big.NewInt(1000000))
	value := BigIntToHex(amount)
	fmt.Println("这是value:",value)
	passphrase := profile.Keywords
	txid, error := rpc.SendTransaction(from, to, value, passphrase)
	if error != nil {
		return nil, error
	}
	transactionResult, error := rpc.QueryTransaction(txid)
	if error != nil {
		return nil, error
	}
	return transactionResult, nil
}
func BigIntToHex(s *big.Int) (res string) {
	res = ""
	b16 := big.NewInt(16)
	var isEnd bool = false
	var c string
	var t = big.NewInt(0)
	for ;; {
		if s.Cmp(b16)>=0 {
			t.Rem(s, b16)
			s.Div(s, b16)
		}else {
			t = s
			isEnd = true
		}
		if t.Cmp(big.NewInt(10))<0 {
			c = t.String()
		}else {
			switch t.Int64() {
			case 10:
				c = "a"
				break
			case 11:
				c = "b"
				break
			case 12:
				c = "c"
				break
			case 13:
				c = "d"
				break
			case 14:
				c = "e"
				break
			case 15:
				c = "f"
				break
			}
		}
		res = c+res
		if isEnd {
			break
		}
	}
	res = "0x" + res
	return res
}